package com.xquant.common.engine.xPP.request;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.xquant.common.engine.xPP.cxf.webservice.ArrayOfContractRoot;
import com.xquant.common.engine.xPP.cxf.webservice.EquityOptionImplContractParam;
import com.xquant.common.engine.xPP.cxf.webservice.SectionSolverParam;
import org.apache.commons.lang.StringUtils;

import java.io.UnsupportedEncodingException;
import java.util.*;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class CalcEngineParam {
    private String requestCode;
    private String priority;
    private int logType = 0;
    private Boolean split = false;
    private String initProductType;
    private String productType;
    private String remark;
    private String draftName;
    private String partyId;
    private String valueDate;

    private CalcInstrumentForm calcInstrumentForm;
    private CalcPricingForm calcPricingForm;
    private CalcResultForm calcResultForm;

    private String upPkRequest;
    @JSONField(serialize = false)
    private String localLog;
    private Instrument instrument;
    private CalcPricingParam calcPricingParam;
    /*反算合约要素   参数*/
    private ArrayOfContractRoot contractRoots;
    /* 反算合约要素 最优区间 */
    private SectionSolverParam sectionSolvers;

    private List<UnderlyingMarket> underlyingMarkets;
    private List<CalcSceneParam> calcSceneParams;
    private Object customPricingParam;

    public SectionSolverParam getSectionSolvers() {
        return sectionSolvers;
    }

    public CalcEngineParam setSectionSolvers(SectionSolverParam sectionSolvers) {
        this.sectionSolvers = sectionSolvers;
        return this;
    }

    public Boolean getSplit() {
        return split;
    }

    public void setSplit(Boolean split) {
        this.split = split;
    }

    public CalcResultForm getCalcResultForm() {
        return calcResultForm;
    }

    public void setCalcResultForm(CalcResultForm calcResultForm) {
        this.calcResultForm = calcResultForm;
    }

    public String getValueDate() {
        return valueDate;
    }

    public void setValueDate(String valueDate) {
        this.valueDate = valueDate;
    }

    public String getRemark() {
        return remark;
    }

    public CalcEngineParam setRemark(String remark) {
        this.remark = remark;
        return this;
    }

    public String getDraftName() {
        return draftName;
    }

    public void setDraftName(String draftName) {
        this.draftName = draftName;
    }

    public String getPartyId() {
        return partyId;
    }

    public void setPartyId(String partyId) {
        this.partyId = partyId;
    }

    public String getInitProductType() {
        return initProductType;
    }

    public void setInitProductType(String initProductType) {
        this.initProductType = initProductType;
    }

    public String getProductType() {
        return productType;
    }

    public void setProductType(String productType) {
        this.productType = productType;
    }

    public CalcInstrumentForm getCalcInstrumentForm() {
        return calcInstrumentForm;
    }

    public void setCalcInstrumentForm(CalcInstrumentForm calcInstrumentForm) {
        this.calcInstrumentForm = calcInstrumentForm;
    }

    public CalcPricingForm getCalcPricingForm() {
        return calcPricingForm;
    }

    public void setCalcPricingForm(CalcPricingForm calcPricingForm) {
        this.calcPricingForm = calcPricingForm;
    }

    public String getUpPkRequest() {
        return upPkRequest;
    }

    public void setUpPkRequest(String upPkRequest) {
        this.upPkRequest = upPkRequest;
    }

    public int getLogType() {
        return logType;
    }

    public CalcEngineParam setLogType(int logType) {
        this.logType = logType;
        return this;
    }

    public String getRequestCode() {
        return requestCode;
    }

    public void setRequestCode(String requestCode) {
        this.requestCode = requestCode;
    }

    public String getPriority() {
        return priority;
    }

    public void setPriority(String priority) {
        this.priority = priority;
    }

    public String getLocalLog() {
        return localLog;
    }

    public void setLocalLog(String localLog) {
        this.localLog = localLog;
    }

    public Instrument getInstrument() {
        return instrument;
    }

    public void setInstrument(Instrument instrument) {
        this.instrument = instrument;
    }

    public CalcPricingParam getCalcPricingParam() {
        return calcPricingParam;
    }

    public void setCalcPricingParam(CalcPricingParam calcPricingParam) {
        this.calcPricingParam = calcPricingParam;
    }

    public List<CalcSceneParam> getCalcSceneParams() {
        return calcSceneParams;
    }

    public void setCalcSceneParams(List<CalcSceneParam> calcSceneParams) {
        this.calcSceneParams = calcSceneParams;
    }

    public Object getCustomPricingParam() {
        return ObjectUtil.isNull(customPricingParam)?"":customPricingParam;
    }

    public void setCustomPricingParam(Object customPricingParam) {
        this.customPricingParam = ObjectUtil.isNull(customPricingParam)?"":customPricingParam;
    }

    public List<UnderlyingMarket> getUnderlyingMarkets() {
        return underlyingMarkets;
    }

    public void setUnderlyingMarkets(List<UnderlyingMarket> underlyingMarkets) {
        this.underlyingMarkets = underlyingMarkets;
    }

    public CalcEngineParam(Instrument instrument, CalcPricingParam calcPricingParam) {
        this.instrument = instrument;
        this.calcPricingParam = calcPricingParam;
    }

    public CalcEngineParam() {
    }

    public ArrayOfContractRoot getContractRoots() {
        return contractRoots;
    }

    public CalcEngineParam setContractRoots(ArrayOfContractRoot contractRoots) {
        this.contractRoots = contractRoots;
        return this;
    }

    public void convertToBASE64() {
        if (StringUtils.isNotBlank(this.getInstrument().getFpml())) {
            this.getInstrument().setFpml(toBase64(this.getInstrument().getFpml()));
        }
        CalcPricingParam calcPricingParam = this.getCalcPricingParam();
        //贴现率
        String disCode = calcPricingParam.getDiscount() == null ? null : calcPricingParam.getDiscount().getCode();
        if (StringUtils.isNotBlank(disCode)) {
            calcPricingParam.getDiscount().setCode(toBase64(disCode));
        }
        //违约率
        String defaultCurve = calcPricingParam.getDefaultCurve() == null ? null : calcPricingParam.getDefaultCurve().getCode();
        if (StringUtils.isNotBlank(defaultCurve)) {
            calcPricingParam.getDefaultCurve().setCode(toBase64(defaultCurve));
        }
        //标的相关性
        String underlyingCorr = calcPricingParam.getUnderlyingCorr() == null ? null : calcPricingParam.getUnderlyingCorr().getCode();
        if (StringUtils.isNotBlank(underlyingCorr)) {
            calcPricingParam.getUnderlyingCorr().setCode(toBase64(underlyingCorr));
        }
        List<UnderlyingPricingParam> list = calcPricingParam.getUnderlyingPricingParams() == null ? null : calcPricingParam.getUnderlyingPricingParams();
        if (list != null) {
            for (UnderlyingPricingParam u : list) {
                //贴现率
                String uDisCode = u.getDiscount() == null ? null : u.getDiscount().getCode();
                if (StringUtils.isNotBlank(uDisCode)) {
                    u.getDiscount().setCode(toBase64(uDisCode));
                }
                //红利
                String dividendCode = u.getDividend() == null ? null : u.getDividend().getCode();
                if (StringUtils.isNotBlank(dividendCode)) {
                    u.getDividend().setCode(toBase64(dividendCode));
                }
                //融资
                String fundingCode = u.getFunding() == null ? null : u.getFunding().getCode();
                if (StringUtils.isNotBlank(fundingCode)) {
                    u.getFunding().setCode(toBase64(fundingCode));
                }
                //波动率
                String volSurfaceCode = u.getVolSurface() == null ? null : u.getVolSurface().getCode();
                if (StringUtils.isNotBlank(volSurfaceCode)) {
                    u.getVolSurface().setCode(toBase64(volSurfaceCode));
                }
                //汇率波动率
                String fxVolSurfaceCode = u.getFxVolSurface() == null ? null : u.getFxVolSurface().getCode();
                if (StringUtils.isNotBlank(fxVolSurfaceCode)) {
                    u.getFxVolSurface().setCode(toBase64(fxVolSurfaceCode));
                }
                //远期
                String forwardCode = u.getForward() == null ? null : u.getForward().getCode();
                if (StringUtils.isNotBlank(forwardCode)) {
                    u.getForward().setCode(toBase64(forwardCode));
                }
                if (u.getUnderlyingCurveCodes() != null) {
                    if (u.getUnderlyingCurveCodes().getForwardPriceCurveCode() != null) {
                        u.getUnderlyingCurveCodes().setForwardPriceCurveCode(
                                toBase64(u.getUnderlyingCurveCodes().getForwardPriceCurveCode()));
                    }
                    if (u.getUnderlyingCurveCodes().getQuantoForwardPriceCurveCode() != null) {
                        u.getUnderlyingCurveCodes().setQuantoForwardPriceCurveCode(
                                toBase64(u.getUnderlyingCurveCodes().getQuantoForwardPriceCurveCode()));
                    }
                    if (u.getUnderlyingCurveCodes().getUnderlyingDscCurveCode() != null) {
                        u.getUnderlyingCurveCodes().setUnderlyingDscCurveCode(
                                toBase64(u.getUnderlyingCurveCodes().getUnderlyingDscCurveCode()));
                    }
                    if (u.getUnderlyingCurveCodes().getUnderlyingFwdCurveCode() != null) {
                        u.getUnderlyingCurveCodes().setUnderlyingFwdCurveCode(
                                toBase64(u.getUnderlyingCurveCodes().getUnderlyingFwdCurveCode()));
                    }
                }
            }
        }

    }

    public List<CalcEngineParam> split() {
        List<CalcEngineParam> ret = new ArrayList<>();
        if (calcPricingParam != null && calcPricingParam.getLegParams() != null) {
            Map<String, Instrument> instruments = this.getInstrument().split();
            for (Map.Entry<String, Instrument> m : instruments.entrySet()) {
                CalcEngineParam engineParam = new CalcEngineParam();
                engineParam.setRequestCode(this.requestCode);
                engineParam.setInstrument(m.getValue());

                if (!"IRStreams".equals(m.getValue().getProductType())) {
                    //设置市场数据
                    engineParam.setUnderlyingMarkets(this.underlyingMarkets);
                    //设置自定义参数
                    engineParam.setCustomPricingParam(this.customPricingParam);
                    //设置情景因子
                    engineParam.setCalcSceneParams(this.calcSceneParams);
                }
                //根据legId获取传入的定价参数，没有这创建空参数,并设置legId
                CalcPricingParam pricingParam = calcPricingParam.getCalcPricingParamByLegId(m.getKey());
                pricingParam.setValueDate(calcPricingParam.getValueDate());
                engineParam.setCalcPricingParam(pricingParam);
                ret.add(engineParam);
            }
        } else if (this.getInstrument().getTermsheet().getJSONArray("legs").size() > 1) {
            Map<String, Instrument> instruments = this.getInstrument().split();
            for (Map.Entry<String, Instrument> m : instruments.entrySet()) {
                CalcEngineParam engineParam = JSON.parseObject(JSON.toJSONString(this), CalcEngineParam.class);
                // legId
                engineParam.getCalcPricingParam().setLegId(m.getKey());
                // 金融工具
                engineParam.setInstrument(m.getValue());
                ret.add(engineParam);
            }
        } else {
            ret.add(this);
        }
        return ret;
    }

    public Map<String, CalcSceneParam> buildCalcSceneParamMap() {
        Map ret = new HashMap();
        for (int i = 0; calcSceneParams != null && i < calcSceneParams.size(); i++) {
            ret.put(calcSceneParams.get(i).getSceneID(), calcSceneParams.get(i));
        }
        return ret;
    }

    private String toBase64(String source) {
        try {
            return Base64.getEncoder().encodeToString(source.getBytes("GBK"));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return source;
    }

}
